//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2011 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_CONTAINER_CCHARSET_H_
#define _BUOLA_CONTAINER_CCHARSET_H_

#include <buola/buola.h>
#include <buola/container/crangeset.h>
#include <buola/container/cbitset.h>

namespace buola {

///\addtogroup container
///@{

/////////////////////////////////////////////////////////////////////////////////////////////////

/// character set

/// This is a container of characters, used mostly for testing if a character belongs to some
/// set during parsing.
///
/// Depending on the size of the character type, it is implemented as either a \ref CBitSet
/// or a \ref CRangeSet
///
/// \tparam tChar the integral type.
///
/////////////////////////////////////////////////////////////////////////////////////////////////
    
template<typename tChar>
class CCharSet
{
    typedef typename std::conditional<sizeof(tChar)==1,CBitSet<tChar>,CRangeSet<tChar>>::type tContainer;

public:
    ///default constructor
    
    ///Initially, the char set contains no characters
    CCharSet()
    {}
    
    ///copy constructor
    CCharSet(const CCharSet &pRH)
        :   mRun(pRH.mRun)
    {}
    
    ///move constructor
    CCharSet(CCharSet &&pRH)
        :   mRun(std::move(pRH.mRun))
    {}
    
    ///tests if a character \p pC is part of the set
    bool Test(tChar pC) const
    {
        return mRun.Test(pC);
    }
    
    ///adds the character \p pC to the set
    void Add(tChar pChar)
    {
        mRun.Add(pChar);
    }

    ///adds the range [\p pFirst,\p pLast] to the set
    void Add(tChar pFirst,tChar pLast)
    {
        mRun.Add(pFirst,pLast);
    }
    
    ///adds the characters to the set
    void Add(std::initializer_list<tChar> pList)
    {
        for(tChar c : pList)
            mRun.Add(c);
    }

    ///adds the set \p pSet to this set
    void Add(const CCharSet &pRun)
    {
        mRun.Add(pRun.mRun);
    }

    ///removes the character \p pC from the set
    void Remove(tChar pChar)
    {
        mRun.Remove(pChar);
    }

    ///removes the range [\p pFirst,\p pLast] from the set
    void Remove(tChar pFirst,tChar pLast)
    {
        mRun.Remove(pFirst,pLast);
    }

    ///adds the characters to the set
    void Remove(std::initializer_list<tChar> pList)
    {
        for(tChar c : pList)
            mRun.Remove(c);
    }

    ///removes the set \p pSet from this set
    void Remove(const CCharSet &pRun)
    {
        mRun.Remove(pRun.mRun);
    }

    ///inverts the set
    
    ///Every character from the representable space that was previously not in the set is now in the set, 
    ///and viceversa
    void Invert()
    {
        mRun.Invert();
    }
    
    ///sets this set to be the intersection of itself with \p pSet
    void Intersect(const CCharSet &pRun)
    {
        mRun.Intersect(pRun);
    }

    
    ///toggles all elements present in \p pSet
    void Xor(const CCharSet &pRun)
    {
        mRun.Xor(pRun);
    }

    ///removes all characters from the set
    void clear()
    {
        mRun.Clear();
    }

private:
    tContainer mRun;
};

///@}

/*namespace buola*/ }

#endif
